package com.dure.hotmemory.drawview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.dure.hotmemory.BaseActivity;

import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.Vector;


/**
 * Created by zhanglong on 2016/11/1 16:42.
 * 提供绘制和操作的基础服务
 */
public abstract class BaseSurfaceView extends SurfaceView implements SurfaceHolder.Callback {

    public Context context;
    public BaseActivity baseActivity;


    private GameThread gameThread;

    PointF touchBegin = null;
    PointF touchDragged = null;
    PointF touchEnd = null;

    private static boolean gamePaused = false;

    long startTime;
    long endTime;
    public BaseSurfaceView(Context context) {
        super(context);
        init(context);
    }

    public BaseSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public BaseSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        this.context = context;
        baseActivity = (BaseActivity) context;
        this.getHolder().addCallback(this);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        Log.d("lesleixz", "surfaceDestroyed");
        gameThread.requestExitAndWait();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        //Instantiate game thread
        gameThread = new GameThread();
        //Start game thread
        gameThread.activateGameThread(holder);

    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }


    public abstract void dataUpdate();

    public abstract void drawUpdate(Canvas canvas);

    public class GameThread extends Thread {
        private boolean isGameRunning;
        private SurfaceHolder currentHolder;

        public void activateGameThread(SurfaceHolder holder) {
            isGameRunning = true;
            currentHolder = holder;
            start();
        }

        @Override
        public void run() {
            Canvas gameCanvas = null;
            while (isGameRunning) {
                if (!gamePaused) {
                    startTime = System.currentTimeMillis();

                    if (currentHolder == null)
                        continue;
                    //clear canvas
                    gameCanvas = null;
                    //locking the canvas for screen pixel editing
                    gameCanvas = currentHolder.lockCanvas();

                    if (gameCanvas != null)
                        gameCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
                    else {
                        continue;
                    }

                    handleTouchEvent();
                    //Update game state
                    dataUpdate();
                    //render game state
                    if (gameCanvas != null)
                        drawUpdate(gameCanvas);


                    endTime = System.currentTimeMillis();

                    currentHolder.unlockCanvasAndPost(gameCanvas);
                }
            }
            Log.d("lesleixz", "gameFinished");
        }

        public void requestExitAndWait() {
            isGameRunning = false;

            try {
                join();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            gameThread = null;
        }
    }

    public void enableGameLoop(boolean enable) {
        gamePaused = !enable;
        if (gamePaused) {
            //save state
            saveState();
        }
    }

    public void saveState() {
    }

    public Vector<MyMotionEvent> eventList = new Vector<>();

    public synchronized void handleTouchEvent(){

        List<MyMotionEvent> handledList = new ArrayList<>();

        if (eventList.size() > 0){
            handledList.addAll(eventList);
        }
        for (MyMotionEvent event: handledList) {
            if (event == null)
                continue;
            if (event.motion == MyMotionEvent.Motion.Up) {
                handleInputTouchRelease(event.pointF);
            } else if (event.motion == MyMotionEvent.Motion.Down) {
                handleInputTouchEngage(event.pointF);
            } else if (event.motion == MyMotionEvent.Motion.Move) {
                handleInputTouchDrag(event.pointF);
            }

//            handledList.add(event);
        }
        try{
            eventList.removeAll(handledList);
        }catch (ConcurrentModificationException e){

        }


    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        MyMotionEvent motionEvent = new MyMotionEvent();


        if (event.getAction() == MotionEvent.ACTION_UP) {
            motionEvent.motion = MyMotionEvent.Motion.Up;
            motionEvent.pointF = new PointF(event.getX(), event.getY());
            eventList.add(motionEvent);
//            return super.onTouchEvent(event);
        } else if (event.getAction() == MotionEvent.ACTION_DOWN) {
            motionEvent.motion = MyMotionEvent.Motion.Down;
            motionEvent.pointF = new PointF(event.getX(), event.getY());
            eventList.add(motionEvent);

        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
            motionEvent.motion = MyMotionEvent.Motion.Move;
            motionEvent.pointF = new PointF(event.getX(), event.getY());
            eventList.add(motionEvent);
        }

        return true;
    }

    public abstract void handleInputTouchEngage(PointF point);

    public abstract void handleInputTouchDrag(PointF point);

    public abstract void handleInputTouchRelease(PointF point);


}
